package com.zrrd.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * @author WanJl
 * @version 1.0
 * @title MyAdvice
 * @description 通知类
 * @create 2024/1/30 10:33
 */
//表示将当前类的对象作为Bean放入IOC容器
@Component  //通知类必须配置成SpringIOC容器管理的Bean
//将通知类设置为切面类
@Aspect
public class MyAdvice {

    //设置切入点方法
    //切入点表达式标准格式：动作关键字(访问修饰符  返回值  包名.类/接口名.方法名(参数) 异常名）
    // execution(public User com.zrrd.service.UserService.findById(int))
    @Pointcut("execution(public com.zrrd.pojo.Tea com.zrrd.service.TeaService.queryOneById(..))")//找到连接点方法
    private void pt(){}

    /**
     * 通知方法
     * 设置在切入点方法pt()的前面执行当前的操作，它属于前置通知
     *
     * 前置通知
     *
     * - 名称：@Before
     * - 类型：**==方法注解==**
     * - 位置：通知方法定义上方
     * - 作用：设置当前通知方法与切入点之间的绑定关系，当前通知方法在原始切入点方法前运行
     */
    @Before("pt()")
    public void beforeMethod(){
        System.out.println("我是前置通知方法在切入点方法之前执行了");
    }

    /**
     * 后置通知
     * - 名称：@After
     * - 类型：==**方法注解**==
     * - 位置：通知方法定义上方
     * - 作用：设置当前通知方法与切入点之间的绑定关系，当前通知方法在原始切入点方法后运行
     */
    @After("pt()")
    public void afterMethod() {
        System.out.println("我是..后置通知方法..在切入点方法之后执行了");
    }

    /**
     * 返回后通知
     *
     * - 名称：@AfterReturning（了解）
     * - 类型：**==方法注解==**
     * - 位置：通知方法定义上方
     * - 作用：设置当前通知方法与切入点之间的绑定关系，当前通知方法在原始切入点方法==正常执行完毕后==运行
     */
    @AfterReturning("pt()")
    public void afterReturning() {
        System.out.println("我是..返回后通知通知方法..在切入点方法完全执行并返回后执行了");
    }

    /**
     * 抛出异常后通知
     * - 名称：@AfterThrowing（了解）
     * - 类型：**==方法注解==**
     * - 位置：通知方法定义上方
     * - 作用：设置当前通知方法与切入点之间的绑定关系，当前通知方法在原始切入点方法运行抛出异常后执行
     * - 范例：
     */
    @AfterThrowing("pt()")
    public void afterThrowingMethod() {
        System.out.println("我是..抛出异常后通知方法..在切入点方法抛出异常后执行了");
    }

    /**
     * - 名称：@Around（重点，常用）
     * - 类型：**==方法注解==**
     * - 位置：通知方法定义上方
     * - 作用：设置当前通知方法与切入点之间的绑定关系，当前通知方法在原始切入点方法前后运行
     * - 范例：：
     * @param pjp
     * @return
     * @throws Throwable
     */
    @Around("pt()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("我是环绕通知方法，我在方法之前出现了 ...");
        //表示对原始操作的调用
        Object ret = pjp.proceed();
        System.out.println("我是环绕通知方法，我在方法之后出现了 ...");
        return ret;
    }
}
